import {ElMessage} from 'element-plus'

/**
 * @typedef ApiResponse<T> 响应体
 * @template T
 * @property {number} code 响应码
 * @property {string} message 响应信息
 * @property {T} data 响应数据
 * @property {function:boolean} success 响应是否是成功的
 */

/**
 * @typedef UserInfo 用户信息
 * @property {number} id 用户 id
 * @property {string} name 用户名
 * @property {string} email 用户邮箱
 * @property {number} status 用户状态
 * @property {string} createTime 创建时间
 * @property {string} lastLoginTime 最后登陆时间
 * @property {string} lastUpdateTime 最后更新时间
 * @property {string} avatar 头像
 */

let f = fetch

// mock 模式下使用 mock 数据
if (import.meta.env.MODE === 'mock') {
  const mockHandlers = [
    {
      handler: (url) => url === '/api/users/info',
      data: {
        id: 1,
        name: 'admin',
        email: 'admin@qq.com',
        status: 1,
        createTime: '2021-01-01 00:00:00',
      },
    },
    {
      handler: (url, options) => url === '/api/sessions' && options.body.get('username') === 'admin',
    },
    {
      handler: url => url === '/api/sessions',
      resp: {
        code: 401,
        message: '用户名或密码错误',
      },
    },
    {
      // 这是一个错误响应 mock 样例，始终放在最后面
      handler: () => true,
      resp: {
        code: 500,
        message: '服务异常，请稍候重试',
      }
    },
  ]
  f = async function () {
    const args = arguments
    const resp = await new Promise((resolve) => {
      for (const h of mockHandlers) {
        if (h.handler.apply(this, args)) {
          setTimeout(() => {
            resolve({
              json: () => {
                if (h.resp) {
                  return h.resp
                }
                return {
                  code: ErrCode.SUCCESS,
                  message: 'SUCCESS',
                  data: h.data,
                }
              },
            })
          }, 1000)
          return
        }
      }
    })
    console.log(...args, resp.json())
    return resp
  }
}

/**
 * 响应的预处理方法，它应该被当前文件内的所有通用 http 方法所使用，用户包裹响应体，增加 success 方法，以及增加未知的错误
 * @param promise
 * @returns {Promise<*>}
 */
async function wrapWithResponse(promise) {
  const resp = await promise.then((resp) => resp.json())
  if (resp.code === ErrCode.ERR_SYSTEM_INTERNAL) {
    ElMessage.error('服务异常，请稍候重试')
    return resp
  }
  resp.success = function () {
    return this.code === ErrCode.SUCCESS
  }
  return resp
}

/**
 * 获取用户信息
 * @returns {Promise<ApiResponse<UserInfo>>} response body json promise
 */
export function getUserInfo() {
  return wrapWithResponse(
    f('/api/users/info', {
      headers: {
        'Content-Type': 'application/json',
      },
      credentials: 'include',
    })
  )
}

/**
 * 登陆
 * @param form 包含 username password 两个用户信息
 * @returns {Promise<any>} 登陆响应
 */
export async function login(form) {
  let d = new FormData()
  d.set('username', form.username)
  d.set('password', form.password)
  return wrapWithResponse(
    f('/api/sessions', {
      headers: {
        // 'Content-Type': 'application/x-www-form-urlencoded',
      },
      method: 'POST',
      credentials: 'include',
      body: d,
    })
  )
}

/**
 * 错误码常量
 * @typedef {Object<string, number>} ErrCode
 * @type ErrCode
 */
export const ErrCode = {
  /**
   * 成功响应
   */
  SUCCESS: 0,

  /**
   * 未知错误
   */
  ERR_SYSTEM_INTERNAL: 500,

  /**
   * 用户名或密码错误
   */
  USERNAME_PASSWORD_INVALID: 1002,
}
